﻿#region Using directives

using System;
using System.Collections.Generic;
using System.Text;

using Weazel.Math;

#endregion

namespace Weazel.Badger.Vhdl
{
  public class ConstantDeclaration : TypedComponent, IProcessDeclarativeItem, IDeclarativeItem
  {
    private static int uniqueConstantNameId = -1;

    public static string GetUniqueConstnatName()
    {
      uniqueConstantNameId++;
      return "constant" + uniqueConstantNameId.ToString();
    }

    private Vhdl.Types.TypeSet possibleTypes;

    private string name;
    public string Name
    {
      get
      {
        return name;
      }
    }

    private Integer value;
    public Integer Value
    {
      get
      {
        return value;
      }

      set
      {
        this.value = value;
      }
    }

    public int GetValue()
    {
			return value.ToInt();
    }

    public override Vhdl.Types.TypeSet GetPossibleTypes()
    {
      return possibleTypes;
    }

		public override void SetActualType(Entity entity, Process process, Statements.StatementCollection statements, Vhdl.Types.Type type)
    {
      if (resolved)
      {
        System.Diagnostics.Debug.Assert(Type == type);
        return;
      }

      if (!possibleTypes.Contains(type))
      {
        string message =
          "Constant declaration trying to set a not supported type: " + type.ToString() + " (" + possibleTypes.ToString() + ")";

        throw new TypeResolveException(message);
      }
      
      this.Type = type;
      resolved = true;
    }

    public override bool VerifyType(ref List<VerifyMessage> messages)
    {
      if (!resolved)
      {
        throw new Exception();
      }

      return true;
    }

    public ConstantDeclaration(Vhdl.Types.TypeSet types, GezelType gezelType, string name, Integer value) 
      : base(types.Count == 1 ? types[0] : new Vhdl.Types.UndefinedType(), gezelType)
    {
      this.possibleTypes = types;      
      this.name = name;     
      this.value = value;
    }

    public ConstantDeclaration(Vhdl.Types.Type type, GezelType gezelType, string name, Integer value) 
      : base(type, gezelType)
    {
      System.Diagnostics.Debug.Assert(!object.Equals(type, null) && type != Types.Types.Undefined);

      this.resolved = true;
			this.possibleTypes = new Weazel.Badger.Vhdl.Types.TypeSet(type);
      this.name = name;
      this.value = value;
    }

    public ConstantDeclaration(Vhdl.Types.Type type, GezelType gezelType, Integer value)
      : this(type, gezelType, GetUniqueConstnatName(), value)
    {
    }

    public ConstantDeclaration(Vhdl.Types.TypeSet types, GezelType gezelType, Integer value)
      : this(types, gezelType, GetUniqueConstnatName(), value)
    {
    }

    public void Write(System.CodeDom.Compiler.IndentedTextWriter writer)
    {
      // first format the 'value'
      string v = null;

			if (Type == Types.Types.StdLogic)
			{
				if (value == Integer.One)
					v = "'1'";
				else if (value == Integer.Zero)
					v = "'0'";
				else
				{
					throw new NotSupportedException("Only 0 and 1 are valid std_logic values");
				}
			}
			else if (Type == Types.Types.StdLogicVector)
			{
				v = string.Format("\"{0}\"", value.ToBinaryString().PadLeft(Type.Width, '0'));

				Console.WriteLine("value: " + value.ToHexadecimalString() + " type: " + Type.ToString());

			}
			else if (Type == Types.Types.Integer)
			{
				v = value.ToDecimalString();
			}
			else
			{
				throw new NotSupportedException("Type not supported");
			}
			 
			writer.WriteLine("constant {0} : {1} := {2};",
        name,
        Type.ToString(),
        v
      );
		
    }
  }
}
